#!/usr/bin/python
#
#       evolution_data evo_status.py Version 0.1
#
#       Copyright 2008 David Konsumer <david.konsumer@gmail.com>
#
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

import pygtk
pygtk.require('2.0')

import gtk
import pynotify
import gtk.glade

import gobject

import os
from evolution_data.mail import *
from time import sleep

import gobject, gnomekeyring

name="evo_status"
title = "Evolutuon Status Icon"
description = "Checks Evolution-configured email accounts without Evolution running"
version = "0.1"
website = 'http://code.google.com/p/evolution-data/'
authors = ['David Konsumer <david.konsumer@gmail.com>']

glade_file=os.path.realpath("%s/%s.glade" % (os.path.dirname(__file__), name))

# TODO: add in support for appointment notification


# simple object to store and retrieve 2D data from gconf
# parent_key is the root key
# defaults is a simple model of default data
# dummy for now...
class GconfDataObject:
	def __init__(self, parent_key, defaults):
		self.parent_key = parent_key
		self.defaults = defaults
		self.data=defaults
		self.client = gconf.client_get_default()
		if not self.client.dir_exists(parent_key):
			self.client.add_dir(parent_key, gconf.CLIENT_PRELOAD_NONE)

	def __setitem__(self, key, val):
		self.data[key]=val
		if type(val) == type(True):
			self.client.set_bool('%s/%s' % (self.parent_key, key), val)
		elif type(val) == type(1.00):
			self.client.set_float('%s/%s' % (self.parent_key, key), val)
		elif type(val) == type(1):
			self.client.set_float('%s/%s' % (self.parent_key, key), val)
		else:
			self.client.set_string('%s/%s' % (self.parent_key, key), val)	


	def __getitem__(self, key):
		if type(self.defaults[key]) == type(True):
			self.data[key] = self.client.get_bool('%s/%s' % (self.parent_key, key))
		elif type(self.defaults[key]) == type(1.00):
			self.data[key] = self.client.get_float('%s/%s' % (self.parent_key, key))
		elif type(self.defaults[key]) == type(1):
			self.data[key] = self.client.get_float('%s/%s' % (self.parent_key, key))
		return self.data[key]

	def __iter__(self):
		return self.data.__iter__

	def __len__(self):
		return len(self.data)

	def __delitem__(self,key):
		del self.data[key]
		client.unset('%s/%s' % (self.parent_key, key))
		


class EvoStatusIcon(gtk.StatusIcon):
	def __init__(self, config={}, icon='evolution'):
		self.icon=icon
		
		# Identify myself to gtk + gnomekeyring
		gobject.set_application_name(name)
		
		# eventually I'll have sound/command options in dialog
		# using pygst, instead of command-line hack...
		config_defaults = {
			'mail_update' : 10,
		#	'apt_update': 1,
			'click_action' : 'evolution',
			'mail_action' : 'gst-launch-0.10 filesrc location=/usr/share/sounds/ubuntu/stereo/dialog-information.ogg ! decodebin ! audioconvert ! pulsesink',
			'apt_action' : 'gst-launch-0.10 filesrc location=/usr/share/sounds/ubuntu/stereo/dialog-error.ogg ! decodebin ! audioconvert ! pulsesink',
			'mail_notify' : True,
		#	'apt_notify' : False,
		}
		
		for i in config_defaults:
			if not config.has_key(i):
				config[i]=config_defaults[i]
		config_defaults = config
		self.config = GconfDataObject('/apps/' + name, config_defaults)
		
		gtk.StatusIcon.__init__(self)
		self.menu = gtk.Menu()
		
		menuItem = gtk.ImageMenuItem(gtk.STOCK_REFRESH)
		menuItem.connect('activate', self.update_email)
		self.menu.append(menuItem)
		
		menuItem = gtk.ImageMenuItem(gtk.STOCK_PREFERENCES)
		menuItem.connect('activate', self.on_preferences)
		self.menu.append(menuItem)
		
		menuItem = gtk.ImageMenuItem(gtk.STOCK_ABOUT)
		menuItem.connect('activate', self.on_about)
		self.menu.append(menuItem)
		
		menuItem = gtk.ImageMenuItem(gtk.STOCK_QUIT)
		menuItem.connect('activate', self.close)
		self.menu.append(menuItem)
		
		self.menu.show_all()
		
		self.set_from_icon_name(self.icon)
		self.set_tooltip('No new messages.')
		self.set_visible(True)
		
		self.connect('activate', self.on_activate)
		self.connect('popup-menu', self.on_popup_menu, self.menu)
		
		pynotify.init(name)
		
		self.email = EvolutionMail()
		self.email.update_accounts()
		
		# get timer rolling	
		#if self.config['apt_update'] > 0:
		#	self.atimer = gobject.timeout_add (self.config['apt_update']*60000, self.update_apt, self)
		if self.config['mail_update'] > 0:
			self.mtimer = gobject.timeout_add (int(self.config['mail_update']*60000), self.update_email, self)
		
		# initial update
		self.update_apt()
		self.update_email()
	
	# main shutdown
	def close(self, *args):
		gtk.main_quit()
	
	# load preferences from gconf, and update GUI
	def load_preferences(self):				
		self.pTree.get_widget("spinbuttonMailUpdate").set_value(self.config['mail_update'])
		#self.pTree.get_widget("spinbuttonAppointmentUpdate").set_value(self.config['apt_update'])
		self.pTree.get_widget("entryClick").set_text(self.config['click_action'])
		self.pTree.get_widget("entryNewMail").set_text(self.config['mail_action'])
		#self.pTree.get_widget("entryAppointment").set_text(self.config['apt_action'])
		self.pTree.get_widget("checkbuttonAlertEmail").set_active(self.config['mail_notify'])
		#self.pTree.get_widget("checkbuttonAlertApt").set_active(self.config['apt_notify'])
		
	
	# save preferences to gconf, from GUI
	def save_preferences(self, *args):
		self.config['mail_update'] = self.pTree.get_widget("spinbuttonMailUpdate").get_value()
		#self.config['apt_update'] = self.pTree.get_widget("spinbuttonAppointmentUpdate").get_value()
		self.config['click_action'] = self.pTree.get_widget("entryClick").get_text()
		self.config['mail_action'] = self.pTree.get_widget("entryNewMail").get_text()
		#self.config['apt_action'] = self.pTree.get_widget("entryAppointment").get_text()	
		self.config['mail_notify'] = self.pTree.get_widget("checkbuttonAlertEmail").get_active()
		#self.config['apt_notify'] = self.pTree.get_widget("checkbuttonAlertApt").get_active()
		
		# close window
		self.preferences_cancel()
		
	# tray icon pressed
	def on_activate(self, data):
		print 'icon pressed.'
		if self.config['click_action']:
			self.bgcmd(self.config['click_action'])

	# load tray menu
	def on_popup_menu(self, widget, button, time, data = None):
		self.menu.popup(None, None, None, button, time)

	# show preference dialog
	def on_preferences(self, *args):
		self.pTree = gtk.glade.XML(glade_file, "windowPreferences")
		self.pWindow = self.pTree.get_widget("windowPreferences")
		self.load_preferences()
		self.pTree.signal_autoconnect(self)		
		self.pWindow.show()		
	
	# close preferences dialog
	def preferences_cancel(self,  *args):
		self.pWindow.destroy()
	
	# show about dialog
	def on_about(self, *args):
		dialog = gtk.AboutDialog()
		dialog.set_name(title)
		dialog.set_version(version)
		dialog.set_comments(description)
		dialog.set_website(website)
		dialog.set_authors(authors)
		dialog.run()
		dialog.destroy()
	
	# check email
	def update_email(self, *args):
		print "update email"
		total_count = 0
		emails={}
		for account in self.email.accounts:
			try:
				a = self.email.accounts[account]
				a['password'] = gnomekeyring.find_network_password_sync(user=a['username'], server=a['server'], protocol="imap")[0]['password']
				emails[account] = self.email.check_mail(account, a['password'])
				total_count += len(emails[account])
			except KeyError:
				# no password means no check...
				print "no password for %s" % account				
		if not total_count:
			self.set_tooltip("No new messages.")
			self.set_property('blinking', False)
		else:
			if self.config['mail_action']:
				self.bgcmd(self.config['mail_action'])
			self.set_tooltip("%s new messages." % total_count)
			self.set_property('blinking', True)
			if self.config['mail_notify']:
				for aid in emails:
					for uid in emails[aid]:
						self.email_popup(aid, emails[aid][uid]['subject'] , emails[aid][uid]['from'], emails[aid][uid]['date'])
		return True
	
	# check apt's
	def update_apt(self, *args):
		print "update apt."
		return True
	
	# show a notification message for a new email
	def email_popup(self, account, subject, author, date):
		message = "From: %s\n" % author
		message += "Subject: %s\n" % subject
		message += "Date: %s\n" % date
		title = "New message on %s" % account
		self.popup(gobject.markup_escape_text(title), gobject.markup_escape_text(message))
		
		
	# generic function to emit a notification
	def popup(self, title, message, priority=1, sticky=False):
		n = pynotify.Notification(title, message, self.icon)
		n.attach_to_status_icon(self)
		if priority == 0:
			n.set_urgency(pynotify.URGENCY_LOW)
		elif priority == 2:
			n.set_urgency(pynotify.URGENCY_CRITICAL)
		if sticky:
			n.set_timeout(pynotify.EXPIRES_NEVER)
		n.show()

	# run command in background
	def bgcmd(self, cmd):
		# there is probably a nicer way to do this
		os.system("%s &" % cmd)

if __name__ == '__main__':
	EvoStatusIcon()
	gtk.main()

